﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using SchemaMonitor;
using SchemaMonitor.json;
using Framework;

using System.Net;
using System.Text;
using System.Web.Script.Serialization;
using System.IO;
using SchemaMonitor.html;

public partial class _Default : System.Web.UI.Page
{

	#region Members
	private CUser _user;
	#endregion

	public string SearchChapters { get { return CWeb.RequestStr("search", CSession.SearchChapters); } }
	public int BookId { get { return CWeb.RequestInt("bookId", CSession.BookId); } }
	public int TagTypeId { get { return CWeb.RequestInt("tagTypeId", CSession.TagTypeId); } }
	public int TagId { get { return CWeb.RequestInt("tagId", CSession.TagId); } }
	public int SectionId { get { return CWeb.RequestInt("sectionId", CSession.SectionId); } }
	public CBook Book { get { return _user.Books.GetById(BookId); } }
	public int PreviewBookId { get { return CWeb.RequestInt("viewBookId"); } }
	public int PreviewSectionId { get { return CWeb.RequestInt("viewSectionId"); } }
	public bool PreviewNoImages { get { return CWeb.RequestBool("noimgs"); } }
	public bool IsAttachment { get { return CWeb.RequestStr("attach").Length > 0; } }
	public int ActiveViewIndex { get { return CWeb.RequestInt("view", CSession.ActiveViewIndex); } }
	public string NodeId { get { return CWeb.RequestStr("nodeId"); } }
	public CSection Section
	{
		get
		{
			if (null == Book)
				return null;
			return Book.Sections.GetById(SectionId);
		}
	}

	#region Init/Prerender
	private void InitUser(string s)
	{
		//Direct access error
		if (string.IsNullOrEmpty(s))
		{
			if (CWeb.RequestStr("f").Length == 0)
			{
				lit.Text = "No signed_request (or code)";
				//LogError(new Exception("No signed_request (or code)"));
				//return;
			}
			_user = new CUser().SelectAll(new CPagingInfo(1))[0];
			return;
		}
		LogError(new Exception("Code: " + s));

		if (null != s)
			UserFromJson(s, ref _user);
	}
	private void UserFromJson(string s, ref CUser user)
	{
		//Get the hash+base64 data
		if (string.IsNullOrEmpty(s))
		{
			s = Request["code"]; //Temp: Detect for study
			if (null != s)
				LogError(new Exception("Received a code: " + s));
			else
				return;
		}



		bool isPostback = CWeb.RequestBool("isPostback");
		string asc = null;
		JavaScriptSerializer jss = new JavaScriptSerializer();
		try
		{
			string[] ss = s.Split((".").ToCharArray());
			string sha256 = ss[0];
			string base64 = ss[1];
			if (0 != base64.Length % 4)
				base64 = base64.Substring(0, base64.Length - base64.Length % 4);
			byte[] b = Convert.FromBase64String(base64);
			asc = ASCIIEncoding.ASCII.GetString(b);
			if (!asc.EndsWith("}"))
			{
				if (!asc.EndsWith("\""))
					asc += "\"}";
				else
					asc += "}";
			}
		}
		catch (Exception ex)
		{
			LogError(ex);
			lit.Text = ex.Message;
			plhAll.Visible = false;
			return;
		}
		try { var d = jss.Deserialize<dynamic>(asc); }
		catch { asc += "}"; LogError(new Exception("Fixed json bracketting error")); }


		try
		{
			//Read the JSON
			var d = jss.Deserialize<dynamic>(asc);
			var dd = new CDict(d);

			//Get the token
			long userId = dd.AsLong("UserId");
			string token = dd.AsStr("oauth_token");
			int expires = dd.AsInt("expires");
			DateTime exp = DateTime.Now.AddSeconds(expires);

			//Create new user...
			user = new CUser();
			user.UserIsActive = true;
			user.UserSchemaId = CSchema.DefaultId;
			user.UserNodeGuid = CNodeRoot.Pad(userId);

			//...or lookup the existing user (WRONG = go to node table first, then user table)
			CUserList matching = user.SelectById(userId);
			if (matching.Count > 0)
			{
				user = matching[0]; //found

				user.UserIsActive = true; //Convert an existing user
										  //if (DateTime.MinValue == user.UserStarted)
										  //    user.UserStarted = DateTime.Now;
			}
			else //New user (store info, add/remove cartman)
			{
				//Store some extra info
				if (null != d["user"])
				{
					user.All = new CNodeList();
					user.UserNode = CNodeRoot.PersistJson("User", "me", d["user"], user);
					user.Save();
				}
			}



			//Main reference point
			_user = user;

			string key = string.Concat("user", _user.UserId);
			var all = (CNodeList)CCache.Get(key);
			if (null != all)
				_user.All = all;
			else
				CCache.Set(key, _user.All);


			//Initial form state
			var u = user.SoftUser;
			//chkShowLogFile.Checked = u.ShowLogging;
			//chkShowAllData.Checked = u.ShowContacts;



			//Always save the token from web (e.g. password may have changed)
			if (!isPostback)
			{
				user.UserToken = token;
				user.UserTokenExpires = exp;
				user.UserTokenHasExpired = false;
				user.Save();

				//Try to extend it (if its indeed a short token)
				if (user.UserTokenExpires.AddHours(-3) < DateTime.Now)
					try
					{ CEngine.ExtendLifeOfToken(user); }   //Time-delay
					catch (Exception ex)
					{ LogError(ex); }  //Minor errors won't matter
			}

			/*
			//Start a checking thread (if its been 2mins since the last check)
			CCheckList last = new CCheck().SelectByUserId(new CPagingInfo(1, 0, "CheckId", true), userId);
			if (0 == last.Count || last[0].CheckStarted.AddMinutes(2) < DateTime.Now)
				new System.Threading.ThreadStart(StartChecksInThread).BeginInvoke(null, null);// StartChecksInTShread(userId);
				*/
		}
		catch (Exception ex)
		{
			LogError(ex);
			lit.Text = ex.Message;
			return;
		}
	}
	protected void Page_Init(object sender, EventArgs e)
	{
		string s = Request["signed_request"];
		InitUser(s);
		if (null == _user)
		{
			if (lit.Text.Length == 0)
			{
				var err = new CError().SelectAll(new CPagingInfo(1))[0];
				lit.Text = string.Concat("<pre>", err.ErrorMessage, "</pre><pre>", err.ErrorStacktrace, "</pre>");
			}
			return;
		}

		if (PreviewBookId > 0)
		{
			var book = CBook.Cache.GetById(PreviewBookId);
			if (IsAttachment)
				Response.AddHeader("content-disposition", "attachment;filename=" + book.BookName + ".htm");
			else
				Response.AddHeader("content-disposition", "inline;filename=" + book.BookName + ".htm");

			Response.ContentType = "text/html";
			Response.Write(CGenerate.ToHtml(book, _user, PreviewSectionId, PreviewNoImages));
			Response.End();
		}

		CTextbox.OnReturnPress(txtNewSections, btnNewSections);



		//Events
		btnNewBook.Click += BtnNewBook_Click;
		ctrlBooks.AddClick += CtrlBooks_AddClick;
		ctrlSections.AddClick += CtrlSections_AddClick;

		//Actions
		if (SectionId == -2)
			btnNewSections_Click(null, null);


		//Keep the postbacks on the page (checkboxes and paging control)
		this.Form.Action = string.Concat("?signed_request=", s, "&isPostback=true");
		ctrlPagingAdded.FriendlyUrl = "~/default.aspx" + this.Form.Action;
		ctrlPagingDeletes.FriendlyUrl = "~/default.aspx" + this.Form.Action;
		ctrlPagingUpdates.FriendlyUrl = "~/default.aspx" + this.Form.Action;
		ctrlPagingChecks.FriendlyUrl = "~/default.aspx" + this.Form.Action;
		ctrlPagingNewMem.FriendlyUrl = "~/default.aspx" + this.Form.Action;




		//Dropdown lists 
		ctrlData.PageInit(_user);

		if (!string.IsNullOrEmpty(NodeId))// || ActiveViewIndex == 4)
		{
			ctrlDataView.Visible = true;
			ctrlDataView.ShowData(_user);
			this.Form.Action = "?" + Request.QueryString.ToString();
		}
		else if (ActiveViewIndex == 4)
		{
			ctrlData.Visible = true;
			ctrlData.ShowData();
		}

		//Default
		if (null == Book)
		{
			ctrlBooks.Display(_user.Books);

			CSession.BookId = 0;
			CSession.SectionId = 0;
			CSession.SearchChapters = string.Empty;
			return;
		}

		//Book
		foreach (var i in _user.Books)
			CDropdown.Add(ddBook, i.NameAndCount, i.BookId);
		CDropdown.BlankItem(ddBook, "-- New Book --");
		CDropdown.SetValue(ddBook, BookId);
		ddBook.Visible = true;		

		
		//plhPreview.Visible = true;
		iframe.Attributes.Add("src", CSitemap.BookView(BookId).Substring(1));
		lnkPreview.NavigateUrl = CSitemap.BookView(BookId);
		lnkExport.NavigateUrl = CSitemap.BookExport(BookId);
		lnkExportNoImg.NavigateUrl = CSitemap.BookExport(BookId, true);
		lnkPreviewSection.NavigateUrl = CSitemap.SectionView(SectionId, BookId);
		ctrlSections.Display(Book.Sections);
		ctrlSections.Visible = Book.Sections.Count > 0;
		if (null == Section)
		{
			CSession.SearchChapters = string.Empty;
			CSession.SectionId = 0;
			return;
		}
		plhPreview.Visible = false;


		//Section
		foreach (var i in Book.Sections)
			CDropdown.Add(ddSection, i.NameAndCount, i.SectionId);
		CDropdown.Add(ddSection, "-- All Sections --", 0);
		CDropdown.BlankItem(ddSection, "-- New Section --");
		ddSection.Visible = true;

		ddBook.Visible = false;
		lnkBook.Visible = true;
		lnkBook.Text = Book.BookName;
		lnkBook.NavigateUrl = CSitemap.BookEdit(BookId);


		CDropdown.SetValue(ddSection, SectionId);
		ctrlChapters.Display(Section, SearchChapters, _user);

	}

	private void Page_PreRender(object sender, EventArgs e)
	{

		//Check User
		if (null == _user)// || lit.Text.Length > 0)
		{
			plhAll.Visible = false;
			return;
		}
		var userId = _user.UserId;
		CUser user = _user;


		//lnkBooks.Text = CUtilities.NameAndCount(lnkBooks.Text, user.Books);
		var hasBooks = _user.Books.Count > 0;
		ctrlBooks.Visible = hasBooks;
		//plhNewBook.Visible = !hasBooks;

		var bookIsSelected = (null != Book);
		divBooks.Visible = !bookIsSelected;
		litSpacer1.Visible = bookIsSelected;

		litSpacer2.Visible = (null != Section);

		mv.ActiveViewIndex = this.ActiveViewIndex;
		menu_Click(null, null);

		//Apply User Id, urls
		lnkFrequent.HRef += userId.ToString();
		lnkDonateImg.NavigateUrl += userId.ToString();
		lnkDonate.HRef = lnkDonateImg.NavigateUrl;

		lnkName.Text = user.UserName;
		lnkName.NavigateUrl = string.Concat("http://www.facebook.com/profile.php?id=", user.UserId);


		if (mv.ActiveViewIndex == 0)
			ShowIntro();

		if (mv.ActiveViewIndex == 1)
			ShowBook();

		if (mv.ActiveViewIndex == 2)
			ShowToken();

		if (mv.ActiveViewIndex == 3)
			ShowChanges(userId);

		if (mv.ActiveViewIndex == 4)
			ShowData();

		if (mv.ActiveViewIndex == 5)
			ShowLogs();

		if (mv.ActiveViewIndex == 6)
			ShowAdmin();

		if (mv.ActiveViewIndex == 7)
			ShowTypes();

		if (mv.ActiveViewIndex == 8)
			ShowTags();
		

		if (mv.ActiveViewIndex > 8)
			Response.Redirect(CSitemap.PhotoHashAll());

		if (mv.ActiveViewIndex > 8)
			Response.Redirect(CSitemap.PhotoRepeats());
	}
	#endregion

	#region Private
	private void StartChecksInThread()
    {
        System.Threading.Thread.Sleep(500); //Half-sec head-start to complete the page, otherwise it says "failed"
        CUser u = new CUser(_user.UserId); //Isolates it from the one being displayed
        CEngine.Process(u);
		u.ClearData();
    }
	#endregion

	#region Form Events

	private void CtrlBooks_AddClick()
	{
		BtnNewBook_Click(null, null);
	}
	private void CtrlSections_AddClick()
	{
		btnNewSections_Click(null, null);
	}

	private void BtnNewBook_Click(object sender, EventArgs e)
	{
		if (txtNewBook.Text.Length == 0)
			txtNewBook.Text = "Book #" + (1 + _user.Books.Count);

		var b = new CBook();
		b.BookName = txtNewBook.Text;
		b.BookUserId = _user.UserId;
		b.Save();

		Response.Redirect(CSitemap.BookEdit(b.BookId));
	}
	protected void btnNewSections_Click(object sender, EventArgs e)
	{
		if (null == Book)
			return;

		var n = txtNewSections.Text;
		if (n.Length == 0)
			n = "Section #" + (1 + Book.SectionCount);

		var s = new CSection();
		s.SectionName = n;
		s.SectionBookId = BookId;
		s.SectionSortOrder = Book.SectionCount;
		s.Save();

		Response.Redirect(CSitemap.BookEdit(BookId));
	}


	protected void btnUpdateBookName_Click(object sender, EventArgs e)
	{
		if (null == Book)
			return;
		Book.BookName = txtBookName.Text;
		Book.Save();
		Response.Redirect(CSitemap.BookEdit(BookId));
	}
	protected void btnUpdateSectionName_Click(object sender, EventArgs e)
	{
		if (null == Section)
			return;
		Section.SectionName = txtSectionName.Text;
		Section.Save();
		Response.Redirect(CSitemap.SectionEdit(Section));
	}

	protected void btn_Click(object sender, EventArgs e)
    {
        if (null == _user)
            return;
        _user.UserToken = txtToken.Text;
        _user.UserTokenExpires = DateTime.Now.AddHours(3);
        _user.UserIsActive = true;
        _user.Save();
        Response.Redirect(Request.RawUrl);
    }
    protected void menu_Click(object sender, MenuEventArgs e)
    {
        int v = mv.ActiveViewIndex;
        string s = v.ToString();
		if (null != e)
		{
			s = e.Item.Value;
			v = int.Parse(s);
			mv.ActiveViewIndex = v;
		}

        foreach (MenuItem i in menu.Items)
            i.Selected = (s == i.Value);

		CSession.ActiveViewIndex = v;
		if (null != sender)
			Response.Redirect(Request.RawUrl, true);
    }

	protected void btnDeleteLogs_Click(object sender, EventArgs e)
    {
        var c = new CCheck();
        c.DeleteWhere("CheckUserId", ESign.EqualTo, _user.UserId);
    }
	protected void ddBook_SelectedIndexChanged(object sender, EventArgs e)
	{
		if (ddBook.SelectedIndex == 0)
			BtnNewBook_Click(sender, e);

		Response.Redirect(CSitemap.BookEdit(CDropdown.GetInt(ddBook)));
	}

	protected void ddSection_SelectedIndexChanged(object sender, EventArgs e)
	{
		if (ddSection.SelectedIndex == 0)
			btnNewSections_Click(null, null);

		var s = Book.Sections.GetById(CDropdown.GetInt( ddSection));
		if (null != s)
			Response.Redirect(CSitemap.SectionEdit(s));
		Response.Redirect(CSitemap.BookEdit(BookId));
	}
	#endregion


	#region Tabs
	private void ShowIntro()
    {
        string totals = (string)CCache.Get("Totals");
        if (null == totals)
        {
            StringBuilder sb = new StringBuilder();
            var countUsers = new CUser().SelectCountByIsActive(true);
            var countNodes = new SchemaMonitor.CNode().SelectCount();
            var countArchi = new CNodesArchived().SelectCount();
            var countChang = new CChange().SelectCount();
            if (countUsers > 0) sb.Append(CUtilities.NameAndCount("Users", countUsers)).Append(", ");
            if (countNodes > 0) sb.Append(CUtilities.NameAndCount("Nodes", countNodes)).Append(", ");
            if (countChang > 0) sb.Append(CUtilities.NameAndCount("Updates", countChang)).Append(", ");
            if (countArchi > 0) sb.Append(CUtilities.NameAndCount("Archive", countArchi)).Append(", ");
            if (sb.Length > 0)
                sb.Remove(sb.Length - 1, 1);
            totals = sb.ToString();
            CCache.Set("Totals", totals, 0, 2); //2min cache
        }
        litCounts.Text = totals;
    }
	private void ShowBook()
	{
		var b = Book;
		if (null == b)
			return;
		CSession.BookId = BookId;

		fs.Visible = true;

		txtBookName.Text = b.BookName;

		var s = Section;
		if (null == s)
			return;
		CSession.SectionId = SectionId;

		fs.Visible = false;
		fsSection.Visible = true;

		txtSectionName.Text = s.SectionName;
	}
    private void ShowToken()
    {
    }
    private void ShowLogs()
    {
        lblFirstCheck.Text = CUtilities.Timespan(_user.UserCreated); //UserStarted
        lblFirstCheck.ToolTip = CUtilities.LongDateTime(_user.UserCreated);

        CCheckList checks = new CCheck().SelectByUserId(ctrlPagingChecks.Info, _user.UserId);
        foreach (CCheck i in checks)
            UCCheck(plhChecks).Display(i);
    }
    private void ShowData()
	{
		ctrlDataView.Visible = true;
		if (NodeId.Length > 0)
		{
			//ctrlDataView.ShowData( _user);
		}
		else
		{
		}
	}

	private void ShowChanges(long userId)
    {
        var n = new SchemaMonitor.CNode();

        //Added Recently
        CPagingInfo pi = ctrlPagingAdded.Info;
        var adds = n.RecentAdds(pi, userId);
        foreach (var i in adds)
            UCNode(plhAdded).Display(i);
        litAddedCount.Text = pi.Count.ToString();
        colRecentAdds.Visible = pi.Count > 0;

        //Deleted Recently
        pi = ctrlPagingDeletes.Info;
        var deletes = n.RecentDeletes(pi, userId);
        foreach (var i in deletes)
            UCNode(plhDeleted).Display(i);
        litDeletedCount.Text = pi.Count.ToString();
        colRecentDeletes.Visible = pi.Count > 0;

        //Changed Recently
        pi = ctrlPagingUpdates.Info;
        var updates = new CChange().SelectByUser(pi, userId);
        foreach (var i in updates)
            UCNode(plhUpdates).Display(i);
        litUpdatedCount.Text = pi.Count.ToString();
        colUpdates.Visible = pi.Count > 0;
    }
    private void ShowTypes()
    {
		CSignature.Cache = null;
		CType.Cache = null;
		CTag.Cache = null;

		foreach (var i in CType.Cache.System)
            UCTypeSimple(plhSystem).Display(i);
        foreach (var i in CType.Cache.Manual)
            UCTypeComplex(plhManual).Display(i);
        foreach (var i in CType.Cache.Auto)
            UCTypeComplex(plhAuto).Display(i);
	}
	private void ShowTags()
	{
		TableRow tr = null;
		TableCell td = null;
		HyperLink lnk = null;
		foreach (var i in CTagType.Cache)
		{
			tr = new TableRow();
			tblTagType.Rows.Add(tr);
			if (0 == tblTagType.Rows.Count % 2)
				tr.CssClass = "alt_row";

			td = new TableCell();
			tr.Cells.Add(td);
			lnk = new HyperLink();
			td.Controls.Add(lnk);
			lnk.Text = i.NameAndCount;
			lnk.NavigateUrl = CSitemap.Tags(i.TypeId);
			lnk.Font.Bold = true;
			if (i.TypeId == TagTypeId)
			{
				lnk.ForeColor = System.Drawing.Color.Black;
				CSession.TagTypeId = TagTypeId;
				txtTypeName.Text = i.TypeName;
				btnSaveTypeName.Text = "Save";
			}

			td = new TableCell();
			tr.Cells.Add(td);
			td.Text = i.TagIsOneToOne ? "One" : "Many";	
		}
		tr = new TableRow();
		tblTagType.Rows.Add(tr);
		td = new TableCell();
		tr.Cells.Add(td);
		lnk = new HyperLink();
		td.Controls.Add(lnk);
		lnk.Text = "[New Tag Type]";
		lnk.NavigateUrl = CSitemap.Tags(0);
		if (0 == TagTypeId)
		{
			lnk.Font.Bold = true;
			lnk.ForeColor = System.Drawing.Color.Black;
			CSession.TagTypeId = TagTypeId;
			txtTypeName.Text = string.Empty;
			btnSaveTypeName.Text = "Add";
		}
		else
			CSession.TagTypeId = TagTypeId;

		td = new TableCell();
		tr.Cells.Add(td);
		td.Text = "&nbsp;";



		if (TagTypeId > 0)
		{
			tr = new TableRow();
			tblTags.Rows.Add(tr);
			tr.CssClass = "alt_row";

			td = new TableCell();
			tr.Cells.Add(td);
			td.ColumnSpan = 3;
			lnk = new HyperLink();
			td.Controls.Add(lnk);
			lnk.Text = "[New Tag]";
			lnk.NavigateUrl = CSitemap.Tags(TagTypeId);
			if (0 >= TagId)
			{
				btnRenameTag.Text = "Add";
				btnDeleteTag.Visible = false;
				lnk.ForeColor = System.Drawing.Color.Black;
				lnk.Font.Bold = true;
			}
			else
				CSession.TagId = TagId;


			var tt = CTagType.Cache.GetById(TagTypeId);
			foreach (var i in tt.MetaTags)
			{
				tr = new TableRow();
				tblTags.Rows.Add(tr);
				if (1 == tblTags.Rows.Count % 2)
					tr.CssClass = "alt_row";

				td = new TableCell();
				tr.Cells.Add(td);
				td.Width = new Unit("100%");

				lnk = new HyperLink();
				td.Controls.Add(lnk);
				lnk.Text = i.TagName;
				lnk.NavigateUrl = CSitemap.Tags(i.TagTypeId, i.TagId);
				if (TagId == i.TagId)
				{
					lnk.Font.Bold = true;
					lnk.ForeColor = System.Drawing.Color.Black;
				}
				td = new TableCell();
				tr.Cells.Add(td);
				td.HorizontalAlign = HorizontalAlign.Right;
				td.Wrap = false;

				lnk = new HyperLink();
				td.Controls.Add(lnk);
				lnk.Text = CUtilities.CountSummary(i.Label_OneToOnes.Count  + i.Labels.Count, "img", "none");
				lnk.NavigateUrl = CSitemap.PhotoHashForTag(i.TagId);


				td = new TableCell();
				tr.Cells.Add(td);
				td.HorizontalAlign = HorizontalAlign.Right;
				td.Wrap = false;

				lnk = new HyperLink();
				td.Controls.Add(lnk);
				lnk.Text = CUtilities.CountSummary(i.NodeLabels_OneToOne.Count  + i.NodeLabels.Count, "post", "none");
				//lnk.NavigateUrl = CSitemap.PhotoHash(i.TagId);
				//dont have a posts for tag page

				if (i.TagId == TagId)
				{
					txtTag.Text = i.TagName;
					txtTag.Visible = true;
					btnRenameTag.Visible = true;
					btnDeleteTag.Visible = true;
					CTextbox.OnReturnPress(txtTypeName, btnSaveTypeName);
					CTextbox.OnReturnPress(txtTag, btnRenameTag);
				}


				td = new TableCell();
				tr.Cells.Add(td);
				td.HorizontalAlign = HorizontalAlign.Right;
				td.Wrap = false;
				td.Text = CTextbox.SetNumber(i.TagAlbumId);
			}

		}
		else
			tblTags.Visible = false;
	}
	private void ShowAdmin()
    {
        colAdmin.Visible = true;

        //Recent users
        CPagingInfo pi = ctrlPagingNewMem.Info;
        pi = new CPagingInfo(pi.PageSize, pi.PageIndex, "UserCreated", true);
        foreach (CUser i in new CUser().SelectByIsActive(pi, true))
            UCNode(plhNewMembers).Display(i);

        litNewMemberCount.Text = pi.Count.ToString();
        ctrlPagingNewMem.Info.Count = pi.Count;
    }
    #endregion


    #region Private - Usercontrols
    private static usercontrols_UCNode UCNode(Control target)
    {
        Control ctrl = target.Page.LoadControl("~/usercontrols/UCNode.ascx");
        target.Controls.Add(ctrl);
        return (usercontrols_UCNode)ctrl;
    }
    private static usercontrols_UCCheck UCCheck(Control target)
    {
        Control ctrl = target.Page.LoadControl("~/usercontrols/UCCheck.ascx");
        target.Controls.Add(ctrl);
        return (usercontrols_UCCheck)ctrl;
    }
    private static usercontrols_UCTypeSimple UCTypeSimple(Control target)
    {
        Control ctrl = target.Page.LoadControl("~/usercontrols/UCTypeSimple.ascx");
        target.Controls.Add(ctrl);
        return (usercontrols_UCTypeSimple)ctrl;
    }
    private static usercontrols_UCTypeComplex UCTypeComplex(Control target)
    {
        Control ctrl = target.Page.LoadControl("~/usercontrols/UCTypeComplex.ascx");
        target.Controls.Add(ctrl);
        return (usercontrols_UCTypeComplex)ctrl;
    }

    #endregion

    #region Private - Debug helper
    void LogError(Exception ex) { LogError(ex, _user); }
    void LogError(Exception ex, CUser user)
    {
        CError e = new CError();
        if (null != user)
        {
            e.ErrorUserId = user.UserId;
            e.ErrorUserName = user.UserName;
        }
        e.ErrorMessage = ex.Message;
        e.ErrorStacktrace = ex.StackTrace??string.Empty;
        if (null != ex.InnerException)
        {
            e.ErrorInnerMessage = ex.InnerException.Message;
            e.ErrorInnerStacktrace = ex.InnerException.StackTrace;
        }

        StringBuilder sb = new StringBuilder();
        foreach (string i in Request.QueryString.Keys)
            sb.Append(i).Append("=").AppendLine(Request.QueryString[i]);
        e.ErrorQuerystring = sb.ToString();
        e.ErrorRawUrl = Request.RawUrl;
        e.ErrorHash = ex.ToString().GetHashCode();
        e.Save();
    }

    void Show(object data) { Show((Dictionary<string, object>)data); }
    void Show(Dictionary<string, object> data)
    {
        foreach (string i in data.Keys)
        {
            object obj = data[i];
            if (obj is Dictionary<string, object>)
            {
                lit.Text += (i + "=<blockquote>");
                Show(obj);
                lit.Text += ("}</blockquote>");
            }
            else
            {
                lit.Text += (i + "=" + data[i].ToString() + "<br/>");
            }
        }
    }
	#endregion




	


	protected void btnExecute_Click(object sender, EventArgs e)
	{
		iframeScript.Attributes.Add("src", "iframe.aspx?userId=" + _user.UserId);
		pnlIframe.Visible = true;

	}


	protected void btnCloneBook_Click(object sender, EventArgs e)
	{
		var b = Book;
		if (null == b)
			return;

		var c = new CBook(b, b.DataSrc);
		c.BookName = "Copy of " + c.BookName;
		c.BookCreated = DateTime.Now;
		c.Save();

		foreach (var i in b.Sections)
		{
			var cc = new CSection(i, i.DataSrc);
			cc.SectionBookId = c.BookId;
			cc.Save();

			foreach (var j in i.Chapters)
			{
				var ccc = new CChapter(j, j.DataSrc);
				ccc.ChapterSectionId = cc.SectionId;
				ccc.Save();
			}
		}
		Response.Redirect(CSitemap.BookEdit(c.BookId));
	}

    protected void btnImportMsg_Click(object sender, EventArgs e)
    {
        if (! fuMsg.HasFile)
        {
            lblImportMsg.Text = "No File uploaded";
            return;
        }
        var name = Path.GetFileName(fuMsg.FileName);
        if (name.ToLower() != "messages.htm")
        {
            lblImportMsg.Text = "Expecting messages.htm, not: " + name;
            return;
        }

        //var threads = CHtml.ExtractMessages(fuMsg.FileContent);
    }
	

	protected void btnPublish_Click(object sender, EventArgs e)
	{
		var u = CSession.User;

		var p = new CPublish();
		p.PublishBookId = BookId;
		p.Save();


		var pss = new CPublishSectionList();
		foreach (var i in Book.Sections)
		{
			var ps = new CPublishSection();
			ps.PubSecSectionId = i.SectionId;
			pss.Add(ps);
		}
		pss.Publish = p;
		pss.SaveAll();

		var pcs = new CPublishChapterList();
		foreach (var i in Book.Sections)
			foreach (var j in i.Chapters) // ("ChapterCreated")
			{
				var node = u.All.GetById(j.ChapterNodeGuid);
				var post = new CSoftPost(node.Root, u);

				var pc = new CPublishChapter();
				pc.PubChapChapterId = i.SectionId;
				pc.PubChapComments = 0;
				if (null != post.Comments)
					pc.PubChapComments = post.Comments.Count;
				pc.PubChapWords = post.Message.Replace("\r\n", "\n").Replace("  ", " ").Replace("\n\n", "\n").Replace("\t\t", "\t").Split(("\n\t ").ToCharArray()).Length;
				pcs.Add(pc);
			}
		pcs.Publish = p;
		pcs.SortByOriginal(u);
		pcs.SaveAll();

		var psi = new CPublishImageList();
		foreach (var i in Book.Sections)
			foreach (var j in i.Chapters)
			{
				var node = u.All.GetById(j.ChapterNodeGuid);
				var post = new CSoftPost(node.Root, u);
				var pics = post.Attachments_ ?? new List<CSoftPhoto>();
				foreach (var k in j.ChapterPictures)
				{
					var pi = new CPublishImage();
					pi.PubImgPictureId = k.PictureId;
					pi.PubImgPictureFileSize = k.PhotoHash.PhotoSize;
					pi.PubImgPictureHasCaption = !string.IsNullOrEmpty(k.PhotoHash.PhotoCaptions);// k.PictureCaptions;
					pi.PubImgPictureComments = 0;
					foreach (var x in pics)
						if (x.Target.HasValue)
						{
							var pic = SchemaMonitor.CPhoto.Cache.GetById(x.Target.Value);
							if (null != pic)
							{
								if (k.PhotoHash.Photos.Contains(pic))
								{
									pi.PubImgPictureComments = x.Comments.Count;
								}
							}
							else
								Console.WriteLine("Deleted pic: " + x.Target.Value);
						}
					psi.Add(pi);
				}
			}
		psi.Publish = p;
		psi.SaveAll();
	}


	protected void btnRenameTag_Click(object sender, EventArgs e)
	{
		var m = CMetaTag.Cache.GetById(CSession.TagId);
		if (null == m)
		{
			if (txtTag.Text.Length == 0)
				return;
			m = new CMetaTag();
			m.TagTypeId = TagTypeId;
		}
		m.TagName = txtTag.Text;
		m.Save();
		Response.Redirect(Request.RawUrl);
	}

	protected void btnDeleteTag_Click(object sender, EventArgs e)
	{
		var m = CMetaTag.Cache.GetById(CSession.TagId);
		if (null != m)
			m.Delete();
		Response.Redirect(Request.RawUrl);
	}

	protected void btnSaveTypeName_Click(object sender, EventArgs e)
	{
		var tt = CTagType.Cache.GetById(CSession.TagTypeId);
		if (null == tt)
			tt = new CTagType();
		tt.TypeName = txtTypeName.Text;
		tt.Save();
		Response.Redirect(CSitemap.Tags(tt.TypeId));
	}

	protected void btnTagSection_Click(object sender, EventArgs e)
	{
		var s = txtTagSection.Text;
		if (s.Length == 0)
			return;
		var type = CTagType.Cache.FB_Post;
		var tag = CMetaTag.Cache.GetOrCreate(s, type.TypeId);
		foreach (CChapter i in Section.Chapters)
		{
			var nl = CNodeLabel.Cache.GetById(i.ChapterNodeGuid, tag.TagId);
			if (null == nl)
			{
				nl = new CNodeLabel();
				nl.LabelNodeGuid = i.ChapterNodeGuid;
				nl.LabelTagId = tag.TagId;
				nl.Save();
			}
		}
		Response.Redirect(Request.RawUrl);
	}
}